package astar.model;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;

import astar.controller.Main;

/**
*
* @author Artur Ataide, Andre Ventura
*
*/
public class ReadImage{

	private BufferedImage img;
	private int[][] pixels;
	private double[][] pixelsDouble;

	/**
	*
	* Método Construtor da classe que abre a imagem PGM e a grava para um
	* BufferedReader, podendo assim ser lida e mostrada aos utilizadores.
	* Gera o BufferedReader, preenche o array dos pixels e tranforma-o para 
	* double.
	*
	* @param filename Nome do ficheiro a ser lido.
	*
	*/
	public ReadImage(String filename){
		// array bi-dimensional de doubles contendo o pixel de cada ponto.
		this.pixels = null;
		this.readPGM(filename);
		if(pixels != null) this.pixToImg();
		this.convertPixels();
	}
	
	/**
	*
	* Método que lê a imagem PGM linha a linha. Verifica o tipo de imagem, sendo
	* ela PGM neste caso (P2), o número de linhas, o número de colunas e o seu 
	* valor máximo. Obtem os pixeis através dessa leitura linha a linha, estando
	* eles localizados após o header da imagem.
	*
	* @param filename Nome do ficheiro a ser lido.
	*
	*/
	public void readPGM(String filename){
		try{
			// inicializa o scanner para que a imagem PGM seja lida linha a linha.
			Scanner infile = new Scanner(new BufferedReader (
				new InputStreamReader(
					Main.class.getResourceAsStream(filename))));

			String filetype = infile.nextLine();

			// Verifica se o formato é PGM (p2).
			if(!filetype.equalsIgnoreCase("p2")) {
				System.out.println("[readPGM] Cannot load the image type of "
					+ filetype);
				return;
			}

			// obtém o número de linhas, o número de colunas e o valor máximo.
			infile.nextLine();
			int cols = infile.nextInt();
			int rows = infile.nextInt();
			int maxValue = infile.nextInt();
			this.pixels = new int[rows][cols];

			// lê a restante imagem e guarda-a no array 'pixels'.
			for(int r = 0; r < rows; r++){
				for (int c = 0; c < cols ; c++) {
					this.pixels[r][c] = (int)(infile.nextInt() * 
						255.0 / maxValue);					
				}
			}

			infile.close();			
		} catch (Exception e){
			System.out.println(e.toString() + " caught in read PGM.");
			e.printStackTrace();
		}
	}

	/**
	*
	* Método que converte pixies para uma BufferedImage, desta forma a imagem
	* poderá ser mostrada na JFrame criada em controller.Main.
	*
	*
	*/
	private void pixToImg(){
		int g;

		this.img = new BufferedImage(this.pixels[0].length, this.pixels.length, 
			BufferedImage.TYPE_INT_ARGB);

		for(int row = 0; row < this.pixels.length; ++row){
			for(int col = 0; col < this.pixels[row].length; ++col){
				g = this.pixels[row][col];
				this.img.setRGB(col, row, ((255 << 24) | (g << 16) | (g << 8) | 
					g));
			}
		}

	}

	/**
	*
	* Método que converte os pixeis de inteiros para doubles (visto que esses
	* pixies irão ser normalizados) e troca a ordem das linhas e colunas.
	* As linhas e colunas estavam invertidas para que a imagem pudesse ser
	* apresentada de forma correta.
	*
	*/
	private void convertPixels(){
		this.pixelsDouble = new double[this.pixels.length][this.pixels.length];
		int [][] temp = this.pixels;
		for (int i = 0; i < this.pixels.length; i++) {
			for (int j = 0; j < this.pixels.length; j++) {
				this.pixelsDouble[i][j] = (double)temp[j][i];		
			}
		}
	}

	/**
	*
	* Método que devolve a BufferedImage que irá ser desenhada na JFrame.
	*
	* @return A BufferedImage contendo a imagem a ser desenhada na JFrame.
	*
	*/
	public BufferedImage getImg(){
		return this.img;
	}

	/**
	*
	* Método que devolve o array bi-dimensional contendo os pixies, essencial
	* para o cálculo do algoritmo A*.
	*
	* @return Array bi-dimensional contendo os pixeus da imagem.
	*
	*/
	public double[][] getPixels(){
		return this.pixelsDouble;
	}

}